﻿namespace Extensions.Web.ViewModel
{
    using Extensions.Web.ViewModel.Code;
    using System;
    using System.CodeDom;
    using System.ComponentModel;
    using System.Reflection;
    using System.Web.Compilation;
    using System.Web.UI;

    public class BindingExpressionBuilder : ExpressionBuilder
    {
        private static readonly TypeFilter attributeTypeFilter = new TypeFilter(BindingExpressionBuilder.IAttributeAccessorFilter);
        private static readonly string prefix = "Binding";

        public sealed override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
        {
            if (entry.ExpressionPrefix != prefix)
            {
                throw new Exception("Extensions.ViewModel: ExpressionPrefix is \"Binding\" only.");
            }
            bool flag = entry.ControlType.FindInterfaces(attributeTypeFilter, null).Length > 0;
            if (flag)
            {
                entry.Type = null;
            }
            ExpressionArgs args = new ExpressionArgs(entry.Expression.Trim());
            PropertyDescriptor entryPropertyDescriptor = MemberUtility.GetEntryPropertyDescriptor(entry);
            if (entryPropertyDescriptor != null)
            {
                if (args.IsBuildViewModelBase)
                {
                    this.GetViewModelMaker(args.Expression, context.VirtualPath).AddPropertyWithTry(entryPropertyDescriptor);
                }
                return new CodeSnippetExpression("this.PropertyBinding<" + entry.PropertyInfo.PropertyType.FullName + ">(@__ctrl, typeof(" + entry.ControlType.ToString() + "), \"" + entryPropertyDescriptor.Name + "\", \"" + entry.Expression.Trim() + "\")");
            }
            EventDescriptor entryEventDescriptor = MemberUtility.GetEntryEventDescriptor(entry);
            if (entryEventDescriptor != null)
            {
                if (!flag)
                {
                    throw new Exception("Extensions.ViewModel: '" + entry.ControlID + "' ControlType need derived IAttributeAccessor.");
                }
                if (args.IsBuildViewModelBase)
                {
                    this.GetViewModelMaker(args.Expression, context.VirtualPath).AddEventMethodWithTry(entryEventDescriptor);
                }
                return new CodeSnippetExpression("this.EventBinding(@__ctrl, typeof(" + entry.ControlType.ToString() + "), \"" + entryEventDescriptor.Name + "\", \"" + entry.Expression.Trim() + "\")");
            }
            if (args.IsBuildViewModelBase)
            {
                this.GetViewModelMaker(args.Expression, context.VirtualPath).AddPropertyWithTry(entry.Name);
            }
            return new CodeSnippetExpression("this.AttributeBinding<" + entry.PropertyInfo.PropertyType.FullName + ">(@__ctrl, typeof(" + entry.ControlType.ToString() + "), \"" + entry.Name.ToLower() + "\", \"" + entry.Expression.Trim() + "\")");
        }

        public virtual ViewModelMaker GetViewModelMaker(string expression, string virtualPath)
        {
            return new ViewModelMaker(expression, virtualPath);
        }

        public static bool IAttributeAccessorFilter(Type typeObj, object criteriaObj)
        {
            return (typeObj.ToString() == typeof(IAttributeAccessor).ToString());
        }
    }
}

